/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.archivers.tar.fileEntries.headers;

import com.softwarecraftsmen.orogeny.filing.absolutePathMetaData.AbsolutePathMetaData;
import com.softwarecraftsmen.orogeny.filing.absolutePathMetaData.posixPermissions.PosixClassPermissions;
import com.softwarecraftsmen.orogeny.filing.absolutePathMetaData.posixPermissions.PosixNonClassPermissions;
import static com.softwarecraftsmen.orogeny.filing.absolutePathMetaData.posixPermissions.PosixNonClassPermissions.NoSpecialPermissions;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;

public class FileHeaderWriter
{
	@NonNls
	public static final String EmptyLinkName = "";
	private final FileHeaderFieldWriter writer;

	public FileHeaderWriter(final @NotNull FileHeaderFieldWriter writer)
	{
		this.writer = writer;
	}

	public void writeHeader(final @NotNull String fileName, final @NotNull AbsolutePathMetaData metaData, final @NotNull LinkFlag linkFlag, final @NotNull String linkName)
	{
		writer.writeFileName(fileName);
		writer.writeMode(posixMode(NoSpecialPermissions, metaData.ownerPermissions(), metaData.groupPermissions(), metaData.othersPermissions()));
		writer.writeUserId(metaData.owner().identifier());
		writer.writeGroupId(metaData.group().identifier());
		writer.writeFileSize(metaData.sizeInBytes());
		writer.writeFileModificationTime(metaData.modificationTimeInMillisecondsSince1970());
		writer.writeLinkFlag(linkFlag);
		writer.writeLinkName(linkName);
		writer.writeMagic();
		writer.writeUserName(metaData.owner().name());
		writer.writerGroupName(metaData.group().name());
		writer.writeMajorDeviceId(0);
		writer.writeMinorDeviceId(0);
		writer.pad();
		writer.writeCheckSum();
	}

	private int posixMode(final @NotNull PosixNonClassPermissions posixNonClassPermissions, final @NotNull PosixClassPermissions ownerPermissions, final @NotNull PosixClassPermissions groupPermissions, final @NotNull PosixClassPermissions othersPermissions)
	{
		int posixMode = 0;
		posixMode = setClassPermissions(othersPermissions, 0, posixMode);
		posixMode = setClassPermissions(groupPermissions, 3, posixMode);
		posixMode = setClassPermissions(ownerPermissions, 6, posixMode);
		posixMode = setNonClassPermissions(posixNonClassPermissions, posixMode);
		return posixMode;
	}

	private int setClassPermissions(final PosixClassPermissions posixClassPermissions, final int lowestBitNumber, final int posixModeCurrently)
	{
		int posixMode = setBit(posixModeCurrently, lowestBitNumber, posixClassPermissions.canExecuteOrCanSearchInDirectory());
		posixMode = setBit(posixMode, lowestBitNumber + 1, posixClassPermissions.canWrite());
		posixMode = setBit(posixMode, lowestBitNumber + 2, posixClassPermissions.canRead());
		return posixMode;
	}

	private int setNonClassPermissions(final PosixNonClassPermissions posixNonClassPermissions, final int posixModeCurrently)
	{
		int posixMode = setBit(posixModeCurrently, 9, posixNonClassPermissions.stickyBit());
		posixMode = setBit(posixMode, 10, posixNonClassPermissions.setGroupIdentifierUponExecution());
		posixMode = setBit(posixMode, 11, posixNonClassPermissions.setUserIdentifierUponExecution());
		return posixMode;
	}

	private int setBit(final int posixModeCurrently, final int zeroBasedBitNumber, final boolean setOn)
	{
		if (!setOn)
		{
			return posixModeCurrently;
		}
		return posixModeCurrently | 1 << zeroBasedBitNumber;
	}

}
